package com.aeye.mbr.common.listener;

import com.aeye.mbr.common.plugin.sequence.SnowFlakeSequenceGenerator;
import com.aeye.mbr.common.util.SpringContextUtil;
import com.aeye.mbr.ws.ServiceInvoker;
import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.ReferenceConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import com.alibaba.dubbo.rpc.service.GenericService;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * spring容器初始化完成事件
 * Created by shuzheng on 2017/1/7.
 */
public class ApplicationContextListener implements ApplicationListener<ContextRefreshedEvent> {
    private static ZkClient zkClient;
    private static Logger _log = LoggerFactory.getLogger(ApplicationContextListener.class);
    private String pluginLookup = "";
    private String dataCenterCode = "000000";
    public String getPluginLookup() {
        return pluginLookup;
    }

    public void setPluginLookup(String pluginLookup) {
        this.pluginLookup = pluginLookup;
    }

    public String getDataCenterCode() {
        return dataCenterCode;
    }

    public void setDataCenterCode(String dataCenterCode) {
        this.dataCenterCode = dataCenterCode;
    }

    public static  ApplicationConfig ac = null;
    public static  RegistryConfig rc = null;
    //识别插件
    public static Map<String,ServiceInvoker> webServiceInvokerMap = new ConcurrentHashMap<>();


    public  static ServiceInvoker getServiceInvoker(String fnId,int sysCode){
        return webServiceInvokerMap.get(fnId+"#"+sysCode);
    }

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        if(contextRefreshedEvent.getApplicationContext().getParent() != null)
        {
            return ;
        }
        rc = contextRefreshedEvent.getApplicationContext().getBean(RegistryConfig.class);
        ac = contextRefreshedEvent.getApplicationContext().getBean(ApplicationConfig.class);
        String zkServers = rc.getAddress();
        //注册zookeeper监听器
        if (zkServers.contains("zookeeper://")) {
            zkServers = zkServers.replaceAll("zookeeper://", "");
        }
        zkClient = new ZkClient(zkServers, 5000);
        if(!zkClient.exists("/aeye")){
            zkClient.createPersistent("/aeye");
        }

        if(!zkClient.exists("/aeye/cache")) {
            zkClient.createPersistent("/aeye/cache");
        }

        if(!zkClient.exists("/aeye/worker")) {
            zkClient.createPersistent("/aeye/worker");
        }

        //缓存刷新事件的监听
        List<String> listenCaches = new ArrayList<>();
        final Map<String,CacheListener> map = SpringContextUtil.getBeansOfType(CacheListener.class);
        for(CacheListener l:map.values()){
            listenCaches.addAll(l.getAllListenCacheNames());
        }

        for(String cacheName:listenCaches){
            String path = "/aeye/cache/" + cacheName;
            if(!zkClient.exists(path)) {
                zkClient.createPersistent(path);
            }
            zkClient.subscribeDataChanges(path, new IZkDataListener() {
                @Override
                public void handleDataChange(String s, Object o) throws Exception {
                     String simpleKey = s.replaceAll("/aeye/cache/","");
                     for(CacheListener l:map.values()){
                         l.cacheChanged(simpleKey);
                     }
                }

                @Override
                public void handleDataDeleted(String s) throws Exception {

                }
            });
        }

        //snowFlake 序列生成器初始化
        SnowFlakeSequenceGenerator generator =  contextRefreshedEvent.getApplicationContext().getBean(SnowFlakeSequenceGenerator.class);
        if(generator != null){
            int workerId = -1;
            for(int i = 0; i < 32; i++){
                String node = "/aeye/worker/" + i;
                if(!zkClient.exists(node))
                {
                    zkClient.createEphemeral(node);
                    workerId = i;
                    break;
                }
            }
            generator.initIdWorker(dataCenterCode,workerId);
        }
    }

    private void freshWebServiceMap(List<String> list) {
        //先清空再重新初始化
        webServiceInvokerMap.clear();
        for (String child : list) {
            String[] infos = child.split("_");
            if(infos.length != 3){
                System.out.println("错误的函数类型。" + child);
            }else{
                String fnId = infos[0];
                String aaa666s = infos[1];
                String urlStr = infos[2];
                URL url = URL.valueOf(URL.decode(urlStr));
                for(String aaa666:aaa666s.split(",")){
                    AeyeReferenceInfo rinfo = new AeyeReferenceInfo();
                    rinfo.setInterfaceName(url.getParameter("interface"));
                    rinfo.setVersion(url.getParameter("version"));
                    rinfo.setMethod(fnId);
                    GenericService genericService=initGenericService(rinfo.getInterfaceName());
                    webServiceInvokerMap.put(fnId+"#"+aaa666,new ServiceInvoker(genericService,fnId));
                }
            }
        }
    }

    //初始化每个dubbo的GenericService 方便存入 缓存中
    public GenericService initGenericService(String interFaceName){
        try {
            ReferenceConfig<GenericService> ref=new ReferenceConfig<GenericService>();
            ref.setInterface(interFaceName);//接口名称
            ref.setGeneric(true);
            ref.setApplication(ac);
            ref.setRegistry(rc);
            ref.setGeneric(Constants.GENERIC_SERIALIZATION_NOCHANGE);
            ref.setTimeout(15000);
            GenericService gs=ref.get();
            return gs;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    public static void refreshCache(String cacheKey, String version) {
        String path = "/aeye/cache/" + cacheKey;
        zkClient.writeData(path,version);
    }
}
